package org.jsola.hr.service.impl;

import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import org.apache.commons.lang3.StringUtils;
import org.jsola.common.DateKit;
import org.jsola.core.Page;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.common.HrLogKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IAttendanceRecordDAO;
import org.jsola.hr.dao.IAttendanceStatusDAO;
import org.jsola.hr.dto.AttendanceRecordAddDTO;
import org.jsola.hr.dto.AttendanceRecordUpdateDTO;
import org.jsola.hr.entity.AttendanceRecordDO;
import org.jsola.hr.entity.AttendanceStatusDO;
import org.jsola.hr.query.AttendanceRecordQuery;
import org.jsola.hr.service.IAttendanceDedService;
import org.jsola.hr.service.IAttendanceRecordService;
import org.jsola.hr.vo.AttendanceRecordListVO;
import org.jsola.hr.vo.AttendanceRecordVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import tk.mybatis.mapper.entity.Example;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zhr
 */
@Service("hrAttendanceRecordServiceImpl")
public class AttendanceRecordServiceImpl implements IAttendanceRecordService {

    @Autowired
    private IAttendanceRecordDAO attendanceRecordDAO;

    @Autowired
    private IAttendanceStatusDAO attendanceStatusDAO;

    @Autowired
    private IAttendanceDedService attendanceDedService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public AttendanceRecordVO save(AttendanceRecordAddDTO attendanceRecordAddDTO, TokenUser tokenUser) {
        // 转DO
        AttendanceRecordDO attendanceRecordDO = attendanceRecordAddDTO.to(AttendanceRecordDO.class);
        // 保存
        attendanceRecordDO = save(attendanceRecordDO, tokenUser.getSiteId(), tokenUser.getUserId());
        HrLogKit.logForSave("新增员工考勤记录", "saveAttendanceRecord", attendanceRecordDO.getId(), tokenUser);
        return attendanceRecordDO.to(AttendanceRecordVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(AttendanceRecordUpdateDTO attendanceRecordUpdateDTO, TokenUser tokenUser) {
        //转DO
        AttendanceRecordDO attendanceRecordDO = attendanceRecordUpdateDTO.to(AttendanceRecordDO.class);
        HrLogKit.logForUpdate("修改员工考勤记录", "updateAttendanceRecord", attendanceRecordDO.getId(), tokenUser);
        //根据主键更新，只更新非null值
        return updateByIdSelective(attendanceRecordDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... attendanceRecordIds) {
        HrLogKit.logForDelete("批量删除员工考勤记录", "deleteAttendanceRecordByIds"
                , Arrays.toString(attendanceRecordIds), tokenUser);
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) attendanceRecordIds);
    }


    @Override
    public AttendanceRecordVO selectById(String attendanceRecordId, String siteId) {
        AttendanceRecordDO attendanceRecordDO = selectDOById(attendanceRecordId, siteId);
        if (attendanceRecordDO == null) {
            return null;
        }
        return attendanceRecordDO.to(AttendanceRecordVO.class);
    }

    @Override
    public List<AttendanceRecordListVO> select(AttendanceRecordQuery attendanceRecordQuery, String siteId) {
        List<AttendanceRecordDO> attendanceRecordDOList = selectDO(attendanceRecordQuery, siteId);
        if (CollectionUtils.isEmpty(attendanceRecordDOList)) {
            return attendanceRecordDOList == null ? null : new ArrayList<>();
        }
        return attendanceRecordDOList.stream()
                .map(attendanceRecordDO -> attendanceRecordDO.to(AttendanceRecordListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(AttendanceRecordQuery attendanceRecordQuery, String siteId) {
        Example example = buildExample(attendanceRecordQuery, siteId);
        return attendanceRecordDAO.selectCountByExample(example);
    }

    @Override
    public Page<AttendanceRecordListVO> selectPage(AttendanceRecordQuery attendanceRecordQuery, String siteId) {
        Example example = buildExample(attendanceRecordQuery, siteId);
        Page<AttendanceRecordDO> page = attendanceRecordDAO.selectPageByExample(example,
                attendanceRecordQuery.getPageNo(),
                attendanceRecordQuery.getPageSize());

        return page.to(AttendanceRecordListVO.class);
    }

    @Override
    public AttendanceRecordDO selectDOById(String attendanceRecordId, String siteId) {
        return listById(attendanceRecordId, siteId);
    }

    @Override
    public List<AttendanceRecordDO> selectDO(AttendanceRecordQuery attendanceRecordQuery, String siteId) {
        Example example = buildExample(attendanceRecordQuery, siteId);
        return attendanceRecordDAO.selectByExample(example);
    }


    /**
     * 根据查询参数，构建example
     *
     * @param attendanceRecordQuery 查询参数
     * @param siteId                所属站点id
     * @return example
     */
    private Example buildExample(AttendanceRecordQuery attendanceRecordQuery, String siteId) {
        Example example = new Example(AttendanceRecordDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (attendanceRecordQuery.getEmpId() != null) {
            example.and().andLike("empId", "%" + attendanceRecordQuery.getEmpId() + "%");
        }
        if (attendanceRecordQuery.getNumber() != null) {
            example.and().andLike("number", "%" + attendanceRecordQuery.getNumber() + "%");
        }
        if (attendanceRecordQuery.getDateStart() != null &&
                attendanceRecordQuery.getDateEnd() != null) {
            example.and().andBetween("date", attendanceRecordQuery.getDateStart(),
                    attendanceRecordQuery.getDateEnd());
        }
        if (attendanceRecordQuery.getStartTime() != null) {
            example.and().andEqualTo("startTime", attendanceRecordQuery.getStartTime());
        }
        if (attendanceRecordQuery.getEndTime() != null) {
            example.and().andEqualTo("endTime", attendanceRecordQuery.getEndTime());
        }
        if (attendanceRecordQuery.getStatus() != null) {
            example.and().andEqualTo("status", attendanceRecordQuery.getStatus());
        }
        if (attendanceRecordQuery.getRemark() != null) {
            example.and().andLike("remark", "%" + attendanceRecordQuery.getRemark() + "%");
        }
        if (attendanceRecordQuery.getCompanyId() != null) {
            example.and().andEqualTo("companyId", attendanceRecordQuery.getCompanyId());
        }
        if (attendanceRecordQuery.getGmtCreateStart() != null &&
                attendanceRecordQuery.getGmtCreateEnd() != null) {
            example.and().andBetween("gmtCreate", attendanceRecordQuery.getGmtCreateStart(),
                    attendanceRecordQuery.getGmtCreateEnd());
        }
        if (attendanceRecordQuery.getCreateUserId() != null) {
            example.and().andLike("createUserId", "%" + attendanceRecordQuery.getCreateUserId() + "%");
        }
        if (attendanceRecordQuery.getGmtModifiedStart() != null &&
                attendanceRecordQuery.getGmtModifiedEnd() != null) {
            example.and().andBetween("gmtModified", attendanceRecordQuery.getGmtModifiedStart(),
                    attendanceRecordQuery.getGmtModifiedEnd());
        }
        if (attendanceRecordQuery.getModifiedUserId() != null) {
            example.and().andLike("modifiedUserId", "%" + attendanceRecordQuery.getModifiedUserId() + "%");
        }
        // 排序
        ExampleKit.setExampleOrder(example, attendanceRecordQuery.getOrders());
        return example;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public Boolean attendanceRecordImportExcel(TokenUser tokenUser, MultipartFile file) {
//        ExcelReader reader = ExcelUtil.getReader(ResourceUtil.getStream("1_标准报表.xls"), "考勤记录");
        ExcelReader reader = null;
        try {
            reader = ExcelUtil.getReader(file.getInputStream(), HrConstants.SHEET_NAME);
        } catch (IOException e) {
            e.printStackTrace();
        }
        List<AttendanceRecordDO> attendanceRecordDOList = new ArrayList<>();
        Date now = DateKit.getToday();
        List<List<Object>> read = reader.read();
        //获取年份
        String yearStr = read.get(1).get(2).toString().substring(0, 4);
        //获取月份
        String monthStr = read.get(1).get(2).toString().substring(5, 7);
        //删除导入月份的考勤记录
        Example example = new Example(AttendanceRecordDO.class);
        example.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andCondition("DATE_FORMAT(date ,'%Y-%m') = ", yearStr + "-" + monthStr);
        attendanceRecordDAO.deleteByExample(example);
        String dateStr = "";
        String number = "";
        for (int i = 0; i < read.size(); i++) {
            if (i > 2) {
                List<Object> rowList = read.get(i);
                if ("工 号:".equals(rowList.get(0).toString())) {
                    number = rowList.get(2).toString();
                    //System.out.println(number);
                    continue;
                }
                for (int j = 0; j < rowList.size(); j++) {
                    Object row = rowList.get(j);
                    //获取当前日期
                    if (StringUtils.isBlank(read.get(2).get(j).toString())) {
                        break;
                    }
                    dateStr = yearStr + "-" + monthStr + "-" + read.get(2).get(j).toString();
                    //System.out.println(dateStr);
                    //获取打卡时间
                    String timeStr = read.get(i).get(j).toString() == null ? "" : read.get(i).get(j).toString();
                    String startTimeStr = null;
                    String endTimeStr = null;
                    if (timeStr.length() > 5) {
                        startTimeStr = timeStr.substring(0, 5);
                        endTimeStr = timeStr.substring(timeStr.length() - 5, timeStr.length());
                        //System.out.println(startTimeStr + "~~~~~~~" + endTimeStr);
                    } else if (timeStr.length() == 5) {
                        //一个工作日内只打卡一次（暂时根据时间一点半为分界时间，之前按上班打卡算，之后按下班打卡算）
                        Date timeTmp = DateKit.getDate("HH:mm", timeStr.substring(0, 5));
                        Date timeCompare = DateKit.getDate("HH:mm", HrConstants.TIME_MID_WORK);
                        if (timeTmp.compareTo(timeCompare) == -1) {
                            startTimeStr = timeStr.substring(0, 5);
                        } else {
                            endTimeStr = timeStr.substring(0, 5);
                        }
                    }
                    AttendanceRecordDO attendanceRecordDO = new AttendanceRecordDO();
                    attendanceRecordDO.setNumber(number);
                    attendanceRecordDO.setDate(DateKit.getDate("yyyy-MM-dd", dateStr));
//                    attendanceRecordDO.setStartTime(startTimeStr);
//                    attendanceRecordDO.setEndTime(endTimeStr);
                    attendanceRecordDO.setValid(true);
                    attendanceRecordDO.setSiteId(tokenUser.getSiteId());
                    attendanceRecordDO.setCreateUserId(tokenUser.getUserId());
                    attendanceRecordDO.setGmtCreate(now);
                    attendanceRecordDO.setModifiedUserId(tokenUser.getUserId());
                    attendanceRecordDO.setGmtModified(now);
                    attendanceRecordDOList.add(attendanceRecordDO);
                }
            }
        }
        attendanceRecordDAO.insertListAndSetId(attendanceRecordDOList);

        //异步计算每日考勤状态
        Example exampleStatus = new Example(AttendanceStatusDO.class);
        exampleStatus.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andCondition("DATE_FORMAT(date ,'%Y-%m') = ", yearStr + "-" + monthStr);
        attendanceStatusDAO.deleteByExample(exampleStatus);
        List<AttendanceStatusDO> attendanceStatusDOList = new ArrayList<>();
//        for (AttendanceRecordDO attendanceRecordDO : attendanceRecordDOList) {
//            if(StringUtils.isNotBlank(attendanceRecordDO.getStartTime())){
//                Integer diffStart = DateUtils.getMinutesDiff(DateKit.getDate("HH:mm", attendanceRecordDO.getStartTime()), DateKit.getDate("HH:mm", HrConstants.TIME_TO_WORK));
//                if(diffStart > 0){
//                    //迟到
//                    AttendanceStatusDO attendanceStatusDO = getStatusDOFromRecord(attendanceRecordDO, tokenUser, now, 3, diffStart, "迟到" + diffStart + "分");
//                    attendanceStatusDOList.add(attendanceStatusDO);
//                }
//            }
//            if(StringUtils.isNotBlank(attendanceRecordDO.getEndTime())){
//                Integer diffEnd = DateUtils.getMinutesDiff( DateKit.getDate("HH:mm", HrConstants.TIME_AFTER_WORK), DateKit.getDate("HH:mm", attendanceRecordDO.getEndTime()));
//                if(diffEnd > 0){
//                    //早退
//                    AttendanceStatusDO attendanceStatusDO = getStatusDOFromRecord(attendanceRecordDO, tokenUser, now, 4, diffEnd, "早退" + diffEnd + "分");
//                    attendanceStatusDOList.add(attendanceStatusDO);
//                }
//            }
//            if(StringUtils.isBlank(attendanceRecordDO.getStartTime()) && StringUtils.isBlank(attendanceRecordDO.getEndTime())){
//                //旷工
//                AttendanceStatusDO attendanceStatusDO = getStatusDOFromRecord(attendanceRecordDO, tokenUser, now, 2, null, "旷工");
//                attendanceStatusDOList.add(attendanceStatusDO);
//            }
//        }
        attendanceStatusDAO.insertListAndSetId(attendanceStatusDOList);
        return true;
    }

    public AttendanceStatusDO getStatusDOFromRecord(AttendanceRecordDO attendanceRecordDO, TokenUser tokenUser, Date now, Integer status, Integer minutes, String remarks) {
        AttendanceStatusDO attendanceStatusDO = new AttendanceStatusDO();
        attendanceStatusDO.setRecordId(attendanceRecordDO.getId());
        attendanceStatusDO.setNumber(attendanceRecordDO.getNumber());
        attendanceStatusDO.setDate(attendanceRecordDO.getDate());
        attendanceStatusDO.setStatus(status);
        attendanceStatusDO.setMinutes(minutes);
        attendanceStatusDO.setRemark(remarks);
        attendanceStatusDO.setValid(true);
        attendanceStatusDO.setSiteId(tokenUser.getSiteId());
        attendanceStatusDO.setCreateUserId(tokenUser.getUserId());
        attendanceStatusDO.setGmtCreate(now);
        attendanceStatusDO.setModifiedUserId(tokenUser.getUserId());
        attendanceStatusDO.setGmtModified(now);
        return attendanceStatusDO;
    }
}




